home *** CD-ROM | disk | FTP | other *** search
/ Aminet 21 / Aminet 21 (1997)(GTI - Schatztruhe)[!][Oct 1997].iso / Aminet / gfx / show / gs_src_gs.lha / gs5.03 / iname.c < prev    next >
C/C++ Source or Header  |  1997-05-12  |  18KB  |  603 lines

  1. /* Copyright (C) 1989, 1995, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* iname.c */
  20. /* Name lookup for Ghostscript interpreter */
  21. #include "memory_.h"
  22. #include "string_.h"
  23. #include "ghost.h"
  24. #include "gsstruct.h"
  25. #include "gxobj.h"        /* for o_set_unmarked */
  26. #include "errors.h"
  27. #include "inamedef.h"
  28. #include "imemory.h"            /* for isave.h */
  29. #include "isave.h"
  30. #include "store.h"
  31.  
  32. /* Public values */
  33. const uint name_max_string = max_name_string;
  34.  
  35. /* In the code below, we use the hashing method described in */
  36. /* "Fast Hashing of Variable-Length Text Strings" by Peter K. Pearson, */
  37. /* pp. 677-680, CACM 33(6), June 1990. */
  38.  
  39. /* Define a pseudo-random permutation of the integers 0..255. */
  40. /* Pearson's article claims this permutation gave good results. */
  41. private const far_data byte hash_permutation[256] = {
  42.   1,  87,  49,  12, 176, 178, 102, 166, 121, 193,   6,  84, 249, 230,  44, 163,
  43.  14, 197, 213, 181, 161,  85, 218,  80,  64, 239,  24, 226, 236, 142,  38, 200,
  44. 110, 177, 104, 103, 141, 253, 255,  50,  77, 101,  81,  18,  45,  96,  31, 222,
  45.  25, 107, 190,  70,  86, 237, 240,  34,  72, 242,  20, 214, 244, 227, 149, 235,
  46.  97, 234,  57,  22,  60, 250,  82, 175, 208,   5, 127, 199, 111,  62, 135, 248,
  47. 174, 169, 211,  58,  66, 154, 106, 195, 245, 171,  17, 187, 182, 179,   0, 243,
  48. 132,  56, 148,  75, 128, 133, 158, 100, 130, 126,  91,  13, 153, 246, 216, 219,
  49. 119,  68, 223,  78,  83,  88, 201,  99, 122,  11,  92,  32, 136, 114,  52,  10,
  50. 138,  30,  48, 183, 156,  35,  61,  26, 143,  74, 251,  94, 129, 162,  63, 152,
  51. 170,   7, 115, 167, 241, 206,   3, 150,  55,  59, 151, 220,  90,  53,  23, 131,
  52. 125, 173,  15, 238,  79,  95,  89,  16, 105, 137, 225, 224, 217, 160,  37, 123,
  53. 118,  73,   2, 157,  46, 116,   9, 145, 134, 228, 207, 212, 202, 215,  69, 229,
  54.  27, 188,  67, 124, 168, 252,  42,   4,  29, 108,  21, 247,  19, 205,  39, 203,
  55. 233,  40, 186, 147, 198, 192, 155,  33, 164, 191,  98, 204, 165, 180, 117,  76,
  56. 140,  36, 210, 172,  41,  54, 159,   8, 185, 232, 113, 196, 231,  47, 146, 120,
  57.  51,  65,  28, 144, 254, 221,  93, 189, 194, 139, 112,  43,  71, 109, 184, 209
  58. };
  59.  
  60. /*
  61.  * Definitions and structure for the name table.
  62.  * Entry 0 is left unused.
  63.  * The entry with count = 1 is the entry for the 0-length name.
  64.  * The next nt_1char_size entries (in count order) are 1-character names.
  65.  */
  66. #define nt_1char_size 128
  67. #define nt_1char_first 2
  68. private const far_data byte nt_1char_names[128] = {
  69. #define q8(n) n,n+1,n+2,n+3,n+4,n+5,n+6,n+7
  70. #define q32(n) q8(n),q8(n+8),q8(n+16),q8(n+24)
  71.     q32(0), q32(32), q32(64), q32(96)
  72. #undef q8
  73. };
  74.  
  75. /* Structure descriptors */
  76. gs_private_st_composite(st_name_sub_table, name_sub_table, "name_sub_table",
  77.   name_sub_enum_ptrs, name_sub_reloc_ptrs);
  78. gs_private_st_composite(st_name_table, name_table, "name_table",
  79.   name_table_enum_ptrs, name_table_reloc_ptrs);
  80.  
  81. /* The one and only name table (for now). */
  82. private name_table *the_nt;
  83. private gs_gc_root_t the_nt_root;
  84.  
  85. /* Forward references */
  86. private int name_alloc_sub(P1(name_table *));
  87. private void name_scan_sub(P3(name_table *, uint, bool));
  88.  
  89. /* Debugging printout */
  90. #ifdef DEBUG
  91. private void
  92. name_print(const char *msg, name *pname, uint nidx, const int *pflag)
  93. {    const byte *ptr = pname->string_bytes;
  94.     dprintf1("[n]%s", msg);
  95.     if ( pflag )
  96.       dprintf1("(%d)", *pflag);
  97.     dprintf2(" (0x%lx#%u)", (ulong)pname, nidx);
  98.     debug_print_string(ptr, pname->string_size);
  99.     dprintf2("(0x%lx,%u)\n", (ulong)ptr, pname->string_size);
  100. }
  101. #  define if_debug_name(msg, pname, nidx, pflag)\
  102.      if ( gs_debug_c('n') ) name_print(msg, pname, nidx, pflag)
  103. #else
  104. #  define if_debug_name(msg, pname, nidx, pflag) DO_NOTHING
  105. #endif
  106.  
  107. /* Initialize the name table */
  108. name_table *
  109. name_init(ulong count, gs_memory_t *mem)
  110. {    register int i;
  111.     name_table *nt;
  112.  
  113.     if ( count == 0 )
  114.       count = max_name_count + 1L;
  115.     else if ( count - 1 > max_name_count )
  116.       return 0;
  117.     nt =
  118.       gs_alloc_struct(mem, name_table, &st_name_table, "name_init(nt)");
  119.     the_nt = nt;
  120.     memset(nt, 0, sizeof(name_table));
  121.     nt->max_sub_count =
  122.       ((count - 1) | nt_sub_index_mask) >> nt_log2_sub_size;
  123.     nt->memory = mem;
  124.     /* Initialize the one-character names. */
  125.     /* Start by creating the necessary sub-tables. */
  126.     for ( i = 0; i < nt_1char_first + nt_1char_size; i += nt_sub_size )
  127.       name_alloc_sub(nt);
  128.     for ( i = -1; i < nt_1char_size; i++ )
  129.     {    uint ncnt = nt_1char_first + i;
  130.         uint nidx = name_count_to_index(ncnt);
  131.         register name *pname = name_index_ptr_inline(nt, nidx);
  132.         if ( i < 0 )
  133.           pname->string_bytes = nt_1char_names,
  134.           pname->string_size = 0;
  135.         else
  136.           pname->string_bytes = nt_1char_names + i,
  137.           pname->string_size = 1;
  138.         pname->foreign_string = 1;
  139.         pname->mark = 1;
  140.         pname->pvalue = pv_no_defn;
  141.     }
  142.     /* Reconstruct the free list. */
  143.     nt->free = 0;
  144.     name_trace_finish(NULL);
  145.     /* Register the name table root. */
  146.     gs_register_struct_root(mem, &the_nt_root, (void **)&the_nt,
  147.                 "name table");
  148.     return nt;
  149. }
  150.  
  151. /* Return the one and only table. */
  152. const name_table *
  153. the_name_table(void)
  154. {    return the_nt;
  155. }
  156.  
  157. /* Get the allocator for the name table. */
  158. gs_memory_t *
  159. name_memory(void)
  160. {    return the_nt->memory;
  161. }
  162.  
  163. /* Look up or enter a name in the table. */
  164. /* Return 0 or an error code. */
  165. /* The return may overlap the characters of the string! */
  166. /* See iname.h for the meaning of enterflag. */
  167. int
  168. name_ref(const byte *ptr, uint size, ref *pref, int enterflag)
  169. {    name_table *nt = the_nt;
  170.     register name *pname;
  171.     uint nidx;
  172.     uint *phash;
  173.  
  174.     /* Compute a hash for the string. */
  175.     {    uint hash;
  176.         const byte *p = ptr;
  177.         uint n = size;
  178.         /* Make a special check for 1-character names. */
  179.         switch ( size )
  180.           {
  181.           case 0:
  182.               nidx = name_count_to_index(1);
  183.               pname = name_index_ptr_inline(nt, nidx);
  184.             goto mkn;
  185.           case 1:
  186.             if ( *p < nt_1char_size )
  187.               {    hash = *p + nt_1char_first;
  188.                 nidx = name_count_to_index(hash);
  189.                 pname = name_index_ptr_inline(nt, nidx);
  190.                 goto mkn;
  191.               }
  192.             /* falls through */
  193.           default:
  194.             hash = hash_permutation[*p++];
  195.             while ( --n > 0 )
  196.               hash = (hash << 8) |
  197.                 hash_permutation[(byte)hash ^ *p++];
  198.           }
  199.         phash = nt->hash + (hash & (nt_hash_size - 1));
  200.     }
  201.  
  202.     for ( nidx = *phash; nidx != 0;
  203.           nidx = name_next_index(nidx, pname)
  204.         )
  205.     {    pname = name_index_ptr_inline(nt, nidx);
  206.         if ( pname->string_size == size &&
  207.              !memcmp_inline(ptr, pname->string_bytes, size)
  208.            )
  209.           goto mkn;
  210.     }
  211.     /* Name was not in the table.  Make a new entry. */
  212.     if ( enterflag < 0 )
  213.       return_error(e_undefined);
  214.     if ( size > max_name_string )
  215.       return_error(e_limitcheck);
  216.     nidx = nt->free;
  217.     if ( nidx == 0 )
  218.        {    int code = name_alloc_sub(nt);
  219.         if ( code < 0 ) return code;
  220.         nidx = nt->free;
  221.        }
  222.     pname = name_index_ptr_inline(nt, nidx);
  223.     if ( enterflag == 1 )
  224.     {    byte *cptr = (byte *)gs_alloc_string(nt->memory, size,
  225.                              "name_ref(string)");
  226.         if ( cptr == 0 )
  227.           return_error(e_VMerror);
  228.         memcpy(cptr, ptr, size);
  229.         pname->string_bytes = cptr;
  230.         pname->foreign_string = 0;
  231.     }
  232.     else
  233.     {    pname->string_bytes = ptr;
  234.         pname->foreign_string = (enterflag == 0 ? 1 : 0);
  235.     }
  236.     pname->string_size = size;
  237.     pname->pvalue = pv_no_defn;
  238.     nt->free = name_next_index(nidx, pname);
  239.     set_name_next_index(nidx, pname, *phash);
  240.     *phash = nidx;
  241.     if_debug_name("new name", pname, nidx, &enterflag);
  242. mkn:    make_name(pref, nidx, pname);
  243.     return 0;
  244. }
  245.  
  246. /* Get the string for a name. */
  247. void
  248. name_string_ref(const ref *pnref /* t_name */,
  249.   ref *psref /* result, t_string */)
  250. {    name *pname = pnref->value.pname;
  251.     const name_table *nt = the_nt;
  252.     make_const_string(psref,
  253.               (pname->foreign_string ? avm_foreign :
  254.                imemory_space((gs_ref_memory_t *)nt->memory))
  255.                | a_readonly,
  256.               pname->string_size,
  257.               (const byte *)pname->string_bytes);
  258. }
  259.  
  260. /* Convert a t_string object to a name. */
  261. /* Copy the executable attribute. */
  262. int
  263. name_from_string(const ref *psref, ref *pnref)
  264. {    int exec = r_has_attr(psref, a_executable);
  265.     int code = name_ref(psref->value.bytes, r_size(psref), pnref, 1);
  266.     if ( code < 0 )
  267.       return code;
  268.     if ( exec )
  269.       r_set_attrs(pnref, a_executable);
  270.     return code;
  271. }
  272.  
  273. /* Enter a (permanently allocated) C string as a name. */
  274. int
  275. name_enter_string(const char *str, ref *pref)
  276. {    return name_ref((const byte *)str, strlen(str), pref, 0);
  277. }
  278.  
  279. /* Invalidate the value cache for a name. */
  280. void
  281. name_invalidate_value_cache(const ref *pnref)
  282. {    pnref->value.pname->pvalue = pv_other;
  283. }
  284.  
  285. /* Convert between names and indices. */
  286. #undef name_index
  287. uint
  288. name_index(const ref *pnref)
  289. {    return name_index_inline(pnref);
  290. }
  291. void
  292. name_index_ref(uint index, ref *pnref)
  293. {    name_index_ref_inline(the_nt, index, pnref);
  294. }
  295. name *
  296. name_index_ptr(uint index)
  297. {    return name_index_ptr_inline(the_nt, index);
  298. }
  299.  
  300. /* Get the index of the next valid name. */
  301. /* The argument is 0 or a valid index. */
  302. /* Return 0 if there are no more. */
  303. uint
  304. name_next_valid_index(uint nidx)
  305. {    name_table *nt = the_nt;
  306.     name_sub_table *sub = nt->sub_tables[nidx >> nt_log2_sub_size];
  307.     name *pname;
  308.     do
  309.       { ++nidx;
  310.         if ( (nidx & nt_sub_index_mask) == 0 )
  311.           for ( ; ; nidx += nt_sub_size )
  312.         { if ( (nidx >> nt_log2_sub_size) >= nt->sub_count )
  313.             return 0;
  314.           sub = nt->sub_tables[nidx >> nt_log2_sub_size];
  315.           if ( sub != 0 )
  316.             break;
  317.         }
  318.         pname = &sub->names[nidx & nt_sub_index_mask];
  319.       }
  320.     while ( pname->string_bytes == 0 );
  321.     return nidx;
  322. }
  323.  
  324. /* ------ Garbage collection ------ */
  325.  
  326. /* Unmark all names, except for 1-character permanent names, */
  327. /* before a garbage collection. */
  328. void
  329. name_unmark_all(void)
  330. {    name_table *nt = the_nt;
  331.     uint si;
  332.     name_sub_table *sub;
  333.     for ( si = 0; si < nt->sub_count; ++si )
  334.       if ( (sub = nt->sub_tables[si]) != 0 )
  335.         { uint i;
  336.           for ( i = 0; i < nt_sub_size; ++i )
  337.         sub->names[i].mark = 0;
  338.         }
  339.     { uint ncnt;
  340.       for ( ncnt = 1; ncnt <= nt_1char_size; ++ncnt )
  341.         name_index_ptr(name_count_to_index(ncnt))->mark = 1;
  342.     }
  343. }
  344.  
  345. /* Mark a name.  Return true if new mark.  We export this so we can mark */
  346. /* character names in the character cache. */
  347. bool
  348. name_mark_index(uint nidx)
  349. {    name *pname = name_index_ptr(nidx);
  350.     if ( pname->mark )
  351.       return false;
  352.     pname->mark = 1;
  353.     return true;
  354. }
  355.  
  356. /* Get the object (sub-table) containing a name. */
  357. /* The garbage collector needs this so it can relocate pointers to names. */
  358. void/*obj_header_t*/ *
  359. name_ref_sub_table(const ref *pnref)
  360. {    /* When this procedure is called, the pointers from the name table */
  361.     /* to the sub-tables may or may not have been relocated already, */
  362.     /* so we can't use them.  Instead, we have to work backwards from */
  363.     /* the name pointer itself. */
  364.     return pnref->value.pname - (name_index_inline(pnref) & nt_sub_index_mask);
  365. }
  366. void/*obj_header_t*/ *
  367. name_index_ptr_sub_table(uint index, name *pname)
  368. {    return pname - (index & nt_sub_index_mask);
  369. }
  370.  
  371. /*
  372.  * Clean up the name table after the trace/mark phase of a garbage
  373.  * collection, by removing names that aren't marked.  gcst == NULL indicates
  374.  * we're doing this for initialization or restore rather than for a GC.
  375.  */
  376. void
  377. name_trace_finish(gc_state_t *gcst)
  378. {    name_table *nt = the_nt;
  379.     uint *phash = &nt->hash[0];
  380.     uint i;
  381.  
  382.     for ( i = 0; i < nt_hash_size; phash++, i++ )
  383.        {    uint prev = 0;
  384.         name *pnprev;
  385.         uint nidx = *phash;
  386.         while ( nidx != 0 )
  387.         {    name *pname = name_index_ptr_inline(nt, nidx);
  388.             uint next = name_next_index(nidx, pname);
  389.             if ( pname->mark )
  390.             {    prev = nidx;
  391.                 pnprev = pname;
  392.             }
  393.             else
  394.             {    if_debug_name("GC remove name", pname, nidx,
  395.                           NULL);
  396.                 /* Zero out the string data for the GC. */
  397.                 pname->string_bytes = 0;
  398.                 pname->string_size = 0;
  399.                 if ( prev == 0 )
  400.                   *phash = next;
  401.                 else
  402.                   set_name_next_index(prev, pnprev, next);
  403.             }
  404.             nidx = next;
  405.         }
  406.     }
  407.     /* Reconstruct the free list. */
  408.     nt->free = 0;
  409.     for ( i = nt->sub_count; i--; )
  410.       { name_sub_table *sub = nt->sub_tables[i];
  411.  
  412.         if ( sub != 0 )
  413.           { name_scan_sub(nt, i, true);
  414.             if ( nt->sub_tables[i] == 0 && gcst != 0 )
  415.           { /* Mark the just-freed sub-table as unmarked. */
  416.             o_set_unmarked((obj_header_t *)sub - 1);
  417.           }
  418.           }
  419.         if ( i == 0 )
  420.           break;
  421.       }
  422.     nt->sub_next = 0;
  423. }
  424.  
  425. /* ------ Save/restore ------ */
  426.  
  427. /* Clean up the name table before a restore. */
  428. /* Currently, this is never called, because the name table is allocated */
  429. /* in system VM.  However, for a Level 1 system, we might choose to */
  430. /* allocate the name table in global VM; in this case, this routine */
  431. /* would be called before doing the global part of a top-level restore. */
  432. /* Currently we don't make any attempt to optimize this. */
  433. void
  434. name_restore(alloc_save_t *save)
  435. {    name_table *nt = the_nt;
  436.     /* We simply mark all names older than the save, */
  437.     /* and let name_trace_finish sort everything out. */
  438.     uint si;
  439.     for ( si = 0; si < nt->sub_count; ++si )
  440.       if ( nt->sub_tables[si] != 0 )
  441.         { uint i;
  442.           for ( i = 0; i < nt_sub_size; ++i )
  443.         { name *pname =
  444.             name_index_ptr_inline(nt, (si << nt_log2_sub_size) + i);
  445.           if ( pname->string_bytes == 0 )
  446.             pname->mark = 0;
  447.           else if ( pname->foreign_string )
  448.             pname->mark = 1;
  449.           else
  450.             pname->mark =
  451.               !alloc_is_since_save(pname->string_bytes, save);
  452.         }
  453.         }
  454.     name_trace_finish(NULL);
  455. }
  456.  
  457. /* ------ Internal procedures ------ */
  458.  
  459. /* Allocate the next sub-table. */
  460. private int
  461. name_alloc_sub(name_table *nt)
  462. {    uint sub_index = nt->sub_next;
  463.     name_sub_table *sub;
  464.  
  465.     for ( ; ; ++sub_index )
  466.       {    if ( sub_index > nt->max_sub_count )
  467.           return_error(e_limitcheck);
  468.         if ( nt->sub_tables[sub_index] == 0 )
  469.           break;
  470.       }
  471.     nt->sub_next = sub_index + 1;
  472.     if ( nt->sub_next > nt->sub_count )
  473.       nt->sub_count = nt->sub_next;
  474.     sub = gs_alloc_struct(nt->memory, name_sub_table, &st_name_sub_table,
  475.                   "name_alloc_sub");
  476.     if ( sub == 0 )
  477.       return_error(e_VMerror);
  478.     memset(sub, 0, sizeof(name_sub_table));
  479.     /* The following code is only used if EXTEND_NAMES is non-zero. */
  480.     if ( sub_index >= 0x10000L >> nt_log2_sub_size )
  481.     {    /* Fill in my_extension in all the newly created names. */
  482.         uint extn = sub_index >> (16 - nt_log2_sub_size);
  483.         int i;
  484.         for ( i = 0; i < nt_sub_size; ++i )
  485.           set_name_extension(&sub->names[i], extn);
  486.     }
  487.     nt->sub_tables[sub_index] = sub;
  488.     /* Add the newly allocated entries to the free list. */
  489.     /* Note that the free list will only be properly sorted if */
  490.     /* it was empty initially. */
  491.     name_scan_sub(nt, sub_index, false);
  492. #ifdef DEBUG
  493.     if ( gs_debug_c('n') )
  494.       {    /* Print the lengths of the hash chains. */
  495.         int i0;
  496.         for ( i0 = 0; i0 < nt_hash_size; i0 += 16 )
  497.           {    int i;
  498.             dprintf1("[n]chain %d:", i0);
  499.             for ( i = i0; i < i0 + 16; i++ )
  500.               {    int n = 0;
  501.                 uint nidx;
  502.                 for ( nidx = nt->hash[i]; nidx != 0;
  503.                       nidx = name_next_index(nidx, name_index_ptr_inline(nt, nidx))
  504.                     )
  505.                   n++;
  506.                 dprintf1(" %d", n);
  507.               }
  508.             dputc('\n');
  509.           }
  510.       }
  511. #endif
  512.     return 0;
  513. }
  514.  
  515. /* Scan a sub-table and add unmarked entries to the free list. */
  516. /* We add the entries in decreasing count order, so the free list */
  517. /* will stay sorted.  If all entries are unmarked and free_empty is true, */
  518. /* free the sub-table. */
  519. private void
  520. name_scan_sub(name_table *nt, uint sub_index, bool free_empty)
  521. {    name_sub_table *sub = nt->sub_tables[sub_index];
  522.     uint free = nt->free;
  523.     uint nbase = sub_index << nt_log2_sub_size;
  524.     uint ncnt = nbase + (nt_sub_size - 1);
  525.     bool keep = !free_empty;
  526.  
  527.     if ( sub == 0 )
  528.       return;
  529.     if ( nbase == 0 )
  530.       nbase = 1, keep = true;        /* don't free name 0 */
  531.     for ( ; ; --ncnt )
  532.       {    uint nidx = name_count_to_index(ncnt);
  533.         name *pname = &sub->names[nidx & nt_sub_index_mask];
  534.         if ( pname->mark )
  535.           keep = true;
  536.         else
  537.           { set_name_next_index(nidx, pname, free);
  538.             free = nidx;
  539.           }
  540.         if ( ncnt == nbase )
  541.           break;
  542.       }
  543.     if ( keep )
  544.       nt->free = free;
  545.     else
  546.       {    /* No marked entries, free the sub-table. */
  547.         gs_free_object(nt->memory, sub, "name_scan_sub");
  548.         nt->sub_tables[sub_index] = 0;
  549.         if ( sub_index == nt->sub_count - 1 ) {
  550.           /* Back up over a final run of deleted sub-tables. */
  551.           do {
  552.             --sub_index;
  553.           } while ( nt->sub_tables[sub_index] == 0 );
  554.           nt->sub_count = sub_index + 1;
  555.           if ( nt->sub_next > sub_index )
  556.             nt->sub_next = sub_index;
  557.         } else if ( nt->sub_next == sub_index )
  558.           nt->sub_next--;
  559.       }
  560. }
  561.  
  562. /* Garbage collector enumeration and relocation procedures. */
  563. #define ntptr ((name_table *)vptr)
  564. private ENUM_PTRS_BEGIN_PROC(name_table_enum_ptrs) {
  565.     if ( index >= ntptr->sub_count )
  566.       return 0;
  567.     *pep = ntptr->sub_tables[index];
  568.     return ptr_struct_type;
  569. } ENUM_PTRS_END_PROC
  570. private RELOC_PTRS_BEGIN(name_table_reloc_ptrs) {
  571.     name_sub_table **sub = ntptr->sub_tables;
  572.     uint sub_count = ntptr->sub_count;
  573.     uint i;
  574.     /* Now we can relocate the sub-table pointers. */
  575.     for ( i = 0; i < sub_count; i++, sub++ )
  576.       *sub = gs_reloc_struct_ptr(*sub, gcst);
  577.     /*
  578.      * We also need to relocate the cached value pointers.
  579.      * We don't do this here, but in a separate scan over the
  580.      * permanent dictionaries, at the very end of garbage collection.
  581.      */
  582. } RELOC_PTRS_END
  583. #undef ntptr
  584.  
  585. private ENUM_PTRS_BEGIN_PROC(name_sub_enum_ptrs) {
  586.     return 0;
  587. } ENUM_PTRS_END_PROC
  588. private RELOC_PTRS_BEGIN(name_sub_reloc_ptrs) {
  589.     name *pname = ((name_sub_table *)vptr)->names;
  590.     uint i;
  591.  
  592.     for ( i = 0; i < nt_sub_size; ++pname, ++i ) {
  593.       if ( pname->string_bytes != 0 && !pname->foreign_string ) {
  594.         gs_const_string nstr;
  595.  
  596.         nstr.data = pname->string_bytes;
  597.         nstr.size = pname->string_size;
  598.         gs_reloc_const_string(&nstr, gcst);
  599.         pname->string_bytes = nstr.data;
  600.       }
  601.     }
  602. } RELOC_PTRS_END
  603.